home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / Open Transport / Sample Code / DLPI / OT DLPI Sample1.0B7 / Common Source / HWSpecific.c < prev    next >
Encoding:
Text File  |  1995-07-31  |  15.0 KB  |  469 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        HWSpecific.c
  3.  
  4.     Contains:    This file contains the routine(s) that are hardware specific for the
  5.                 DLPI.  Each vendor must supply code that works with their own
  6.                 card.
  7.                 
  8.     Written by:    
  9.  
  10.     Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.  
  15.     To Do:
  16. */
  17.  
  18. //-----------------------------------------------------------------------------------------
  19. //    Header files
  20. //-----------------------------------------------------------------------------------------
  21.  
  22. #include <OpenTptModule.h>                // Open Transport files
  23. #include <OpenTptDevLinks.h>
  24.  
  25. #include <Interrupts.h>                    // System files
  26. #include <PCI.h>
  27. #include <Kernel.h>
  28. #include <OSUtils.h>
  29. #include <DriverServices.h>
  30.  
  31. #include "PCIRoutines.h"                // our files
  32. #include "DLPIRoutines.h"
  33. #include "HWSpecific.h"
  34. #include "EntryPoints.h"
  35.  
  36. //-----------------------------------------------------------------------------------------
  37. // Global variable for the entire CFM
  38. //-----------------------------------------------------------------------------------------
  39.  
  40. extern    DLPIPrivateData *gDLPIPrivateData;        // Declared in EntryPoints.c
  41.  
  42. //-----------------------------------------------------------------------------------------
  43. //    Description:
  44. //        This routine enables our interrupts based on a parameter passed in.  Code should
  45. //        be added to this routine that enables the various interrupt bits on the card.
  46. //        The enable and disable routines are used by the queue routines to protect
  47. //        critical code sections.  Instead of masking all interrupts we just select
  48. //        the appropriate ones for our card.
  49. //
  50. //    Input:
  51. //        whichIntsOn - turn which interrupts on transmit, receive, or none
  52. //
  53. //    Output:
  54. //        NONE
  55. //
  56. //-----------------------------------------------------------------------------------------
  57. void ABCVendorEnableInterrupts(UInt16 whichIntsOn)
  58. {
  59.  
  60. switch (whichIntsOn)
  61.     {
  62.     case kTxInterrupts:
  63.         // turn on tx interrupts
  64.         break;
  65.     case kRxInterrupts:
  66.         // turn on rx interrupts
  67.         break;
  68.     case kBothTxRxInterrupts:
  69.         // turn on both interrupts
  70.         break;
  71.     default:
  72.         break;
  73.     }
  74.             
  75. }
  76.  
  77. //-----------------------------------------------------------------------------------------
  78. //    Description:
  79. //        This routine disables our interrupts based on a parameter passed in.Code should
  80. //        be added to this routine that disables the various interrupt bits on the card.
  81. //        The enable and disable routines are used by the queue routines to protect
  82. //        critical code sections.  Instead of masking all interrupts we just select
  83. //        the appropriate ones for our card.
  84. //
  85. //    Input:
  86. //        whichIntsOff - turn which interrupts off transmit, receive, or none
  87. //
  88. //    Output:
  89. //        NONE
  90. //
  91. //-----------------------------------------------------------------------------------------
  92. void ABCVendorDisableInterrupts(UInt16 whichIntsOff)
  93. {
  94.  
  95. switch (whichIntsOff)
  96.     {
  97.     case kTxInterrupts:
  98.         // turn off tx interrupts
  99.         break;
  100.     case kRxInterrupts:
  101.         // turn off rx interrupts
  102.         break;
  103.     case kBothTxRxInterrupts:
  104.         // turn off both interrupts
  105.         break;
  106.     default:
  107.         break;
  108.     }
  109.             
  110. }
  111.  
  112. //-----------------------------------------------------------------------------------------
  113. //    Description:
  114. //        This routine should determine if the card pointed to by theID can be used
  115. //        by this driver.  Before we can talk to the card, the card must be enabled.  To
  116. //        enable the card use the Expansion Manager calls to "set" the appropriate
  117. //        address space bit for your card.  
  118. //
  119. //        Always turn off the card after the test has been made.  Just because this routine
  120. //        is executed, it does not mean that the card is going to be used by the system.
  121. //        
  122. //    Input:
  123. //        theID - NameRegistry ID of our pci card
  124. //        resgisterSetAddress - base address of our pci card
  125. //
  126. //    Output:
  127. //        returns true, if driver can work with the card
  128. //        returns false, if driver cannot work with the card
  129. //
  130. //-----------------------------------------------------------------------------------------
  131. Boolean ABCVendorIsThisOurCard(RegEntryID *theID, UInt32 resgisterSetAddress)
  132. {
  133. UInt16    commandValue, newCommandValue, readValue;
  134. OSErr    error;
  135.  
  136. error = ExpMgrConfigReadWord(theID, kPCIConfigCommandRegister,&commandValue);
  137. newCommandValue = commandValue | kIOSpaceEnableBit;    // turn on the card i/o space
  138. error = ExpMgrConfigWriteWord(theID, kPCIConfigCommandRegister, newCommandValue);
  139.  
  140. // CARD REGISTERS ARE NOW ACCESSIBLE!
  141.  
  142. // Remember that the card is little endian and the processor is big endian.
  143. // Long words (32 bits) and words (16 bits) must be swapped.
  144.  
  145. // readValue = *((UInt16 *)(resgisterSetAddress + offset to your register));
  146.  
  147.     // turn card back off
  148. error = ExpMgrConfigWriteWord(theID, kPCIConfigCommandRegister, commandValue);
  149.  
  150. return kTrue;
  151. }
  152.  
  153. //-----------------------------------------------------------------------------------------
  154. //    Description:
  155. //        This routine should set the physical address in the ethernet hw.  On initialization
  156. //        we may have read our physical address out of a EPROM, but now somebody is 
  157. //        explicitly telling us to change our address.  Update in globals.
  158. //
  159. //    Input:
  160. //        physicalAddress - multicast address (array of 6 bytes)
  161. //
  162. //    Output:
  163. //        returns no error
  164. //
  165. //-----------------------------------------------------------------------------------------
  166. SInt32 ABCVendorSetEthernetAddress(UInt8 *physicalAddress)
  167. {
  168.  
  169. OTCopy48BitAddress(physicalAddress,&gDLPIPrivateData->ourEAddress);
  170.  
  171. return kOTNoError;
  172. }
  173.  
  174. //-----------------------------------------------------------------------------------------
  175. //    Description:
  176. //        This routine retrieves the factory ethernet address.  This is not the same
  177. //        as the current ethernet physical address (ourEAddress).
  178. //
  179. //    Input:
  180. //        addressArray - address to place the factory ethernet address bytes
  181. //
  182. //    Output:
  183. //        NONE
  184. //
  185. //-----------------------------------------------------------------------------------------
  186. void ABCVendorGetFactoryEthernetAddress(UInt8 *addressArray)
  187. {
  188. SInt16        index;
  189.  
  190. for (index=0;index != 6;index++) 
  191.     {
  192.     addressArray[index] = index;    // read factory setting from where ever it is stored
  193.     }
  194. }
  195.  
  196. //-----------------------------------------------------------------------------------------
  197. //    Description:
  198. //        This routine enables the hardware to receive a new multicast address.  The
  199. //        address has already been verified that it is a multicast address.  Another
  200. //        check was made before this routine was called that this address is not a 
  201. //        duplicate.  All that needs to be done at this point is manipulate the hardware
  202. //        so that it will start receiving packets whose destination is the address.
  203. //
  204. //    Input:
  205. //        newMulticastAddr - multicast address (array of 6 bytes)
  206. //
  207. //    Output:
  208. //        returns no error
  209. //
  210. //-----------------------------------------------------------------------------------------
  211. SInt32 ABCVendorRegisterMulticast(UInt8 *newMulticastAddr)
  212. {
  213.  
  214. return kOTNoError;
  215. }
  216.  
  217. //-----------------------------------------------------------------------------------------
  218. //    Description:
  219. //        This routine manipulates the hardware in order to not receive the multicast
  220. //        address.  The address was check to see if it had been registered previously.
  221. //        All that needs to be done at this point is manipulate the hardware
  222. //        so that it will stop receiving packets whose destination is the address.
  223. //
  224. //    Input:
  225. //        oldMulticastAddr - multicast address (array of 6 bytes)
  226. //
  227. //    Output:
  228. //        returns no error
  229. //
  230. //-----------------------------------------------------------------------------------------
  231. SInt32 ABCVendorUnregisterMulticast(UInt8 *oldMulticastAddr)
  232. {
  233.  
  234. return kOTNoError;
  235. }
  236.  
  237. //-----------------------------------------------------------------------------------------
  238. //    Description:
  239. //        This routine communicates with the transmitter to send the packet described in 
  240. //        the message block thePacket.  If for some unknown reason you cannot send
  241. //        the packet then drop the packet on the floor.
  242. //
  243. //        Code in this routine demonstrates how to extract the packet data from the
  244. //        message.  This is just a sample, change to fit your hardware.  It is currently
  245. //        commented out since the dma memory ptr is not defined.
  246. //
  247. //    Input:
  248. //        packetSize - byte count of the packet
  249. //        thePacket - message block that describes the packet to transmit
  250. //
  251. //    Output:
  252. //        NONE
  253. //
  254. //-----------------------------------------------------------------------------------------
  255. void ABCVendorTransmitOnePacket(mblk_t *thePacket, UInt16 packetSize)
  256. {
  257.  
  258. #if 0
  259.  
  260. UInt8    *theDMAMemoryPtr;    // this copy algorithm
  261. UInt32    copySize;
  262.  
  263. while (thePacket)
  264.     {
  265.     copySize = thePacket->b_wptr - thePacket->b_rptr;
  266.  
  267.     bcopy((Ptr)thePacket->b_rptr, theDMAMemoryPtr, copySize);
  268.     
  269.     theDMAMemoryPtr += copySize;
  270.     
  271.     thePacket = thePacket->b_cont;
  272.     
  273.     }
  274. #endif
  275.     
  276. }
  277.  
  278. //-----------------------------------------------------------------------------------------
  279. //    Description:
  280. //        This routine needs to check the transmitter hw to determine if it can send
  281. //        a packet with a size of packetSize.
  282. //
  283. //    Input:
  284. //        packetSize - byte count of the packet
  285. //
  286. //    Output:
  287. //        kOTNoError, if the transmitter hw can handle the packet
  288. //        nonzero, if the transmitter hw cannot handle the packet
  289. //
  290. //-----------------------------------------------------------------------------------------
  291. OSErr ABCVendorCheckTransmitterStatus(UInt16 packetSize)
  292. {
  293.  
  294.  
  295.  
  296. return kOTNoError;
  297. }
  298.  
  299. //-----------------------------------------------------------------------------------------
  300. //    Description:
  301. //        This routine first trys to allocate memory for our gDLPIPrivateData.The 
  302. //        hardware should then be initialized.  One of the things during the hw initialization
  303. //        that should be done is to read in our Ethernet address.
  304. //        The gDLPIPrivateData global is set in this routine.
  305. //
  306. //    Input:
  307. //        RegEntryID - NameRegistry ID for our PCI card
  308. //
  309. //    Output:
  310. //        gDLPIPrivateData, NULL if initialization was not successfull
  311. //        !NULL, if initialization was successfull
  312. //
  313. //-----------------------------------------------------------------------------------------
  314.  
  315. void ABCVendorInitialize(RegEntryID *theID)
  316. {
  317. OSStatus    osStatus;
  318. UInt32        amountAllocated;
  319.  
  320.  
  321.     // allocate memory, do not use OT memory unless we need to, OT memory
  322.     //  allocation is interrupt safe so lets not waste it when we can use PoolAlocateResident.
  323.     // Thanks to a developer in Sweden for pointing this out!
  324. gDLPIPrivateData = (DLPIPrivateData *)PoolAllocateResident( sizeof(DLPIPrivateData),kTrue );
  325. if (gDLPIPrivateData == NULL)    
  326.     return;
  327.  
  328. *(&gDLPIPrivateData->nodeEntryID) = *((RegEntryID *)theID);    // copy our reg node id
  329.  
  330. GetPCICardBaseAddress(&gDLPIPrivateData->nodeEntryID,&gDLPIPrivateData->cardBaseAddr,
  331.     kPCIConfigBase10Offset,&amountAllocated);    
  332.     
  333.  
  334. ABCVendorGetFactoryEthernetAddress(gDLPIPrivateData->ourEAddress);        
  335.  
  336.  
  337. // register interrupt handlers
  338. osStatus = InstallISR();        // ignore the error right now!
  339.  
  340. // initialize hardware, remember to turn on the address map bit in the Config Command Register
  341. //    also if the card does dma then you need to turn on the dma (master) bit
  342.  
  343.  
  344. gDLPIPrivateData->TxDeferredTaskCookie = OTCreateDeferredTask(TxDTCallback,NULL);
  345. gDLPIPrivateData->RxDeferredTaskCookie = OTCreateDeferredTask(RxDTCallback,NULL);
  346.  
  347. }
  348.  
  349. //-----------------------------------------------------------------------------------------
  350. //    Description:
  351. //        This routine closes down the hardware.  The memory is also deallocated.  
  352. //        This routine undoes everything done in the initialize routine.
  353. //
  354. //    Input:
  355. //        NONE
  356. //
  357. //    Output:
  358. //        NONE
  359. //
  360. //-----------------------------------------------------------------------------------------
  361.  
  362. void ABCVendorClose(void)
  363. {
  364. OSStatus    osStatus;
  365. mblk_t        *thePacket;
  366.  
  367. // turn off hardware
  368.  
  369. // unregister interrupt handlers
  370. osStatus = UninstallISR();        // ignore the error right now!
  371.  
  372.  
  373. OTDestroyDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
  374. OTDestroyDeferredTask(gDLPIPrivateData->RxDeferredTaskCookie);
  375.  
  376.  
  377.     // clear out the tx and rx dlpi private queues
  378. while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->RxPacketQueue, kNoInterrupts))
  379.     != NULL)
  380.     freemsg(thePacket);
  381.  
  382. while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->TxPacketQueue, kNoInterrupts)) 
  383.     != NULL)
  384.     freemsg(thePacket);
  385.  
  386.     // deallocate memory, must use same routine pair as the allocate
  387. PoolDeallocate(gDLPIPrivateData);
  388. gDLPIPrivateData = NULL;
  389.  
  390. }
  391.  
  392. //-----------------------------------------------------------------------------------------
  393. //    Description:
  394. //        This routine is the interrupt service routine for our card.  Do necessary 
  395. //        stuff in isr then defer for a later time the bulk of the work.  In the isr
  396. //        you need to notify Open Transport that we are in an isr.  The next step
  397. //        is to clear whatever hw bit you need to in order to deassert the interrupt line.
  398. //        
  399. //        For the transmitter...
  400. //            Since the transmitter isr section normally is called after a packet
  401. //            has been transmitted or some error occurs.  You need to cleanup anything
  402. //            related to the packet transmission (collect statistics, ...) and then
  403. //            check the TxPacketQueue to see if you have any packets waiting to
  404. //            be sent.  If there are packets then schedule the deferred task and when
  405. //            the callback occurs it will try to send any packet waiting on the queue.
  406. //
  407. //        For the receiver...
  408. //            If this section is called then you need to collect the packet and place
  409. //            it in a message block.  The message block can then be placed on the 
  410. //            RxPacketQueue.  The callback routine which is called after scheduling the
  411. //            deferred task will check the RxPacketQueue and send all packets on the
  412. //            queue to the appropriate stream.
  413. //
  414. //    Input:
  415. //        member - contains information about the pci interrupt member
  416. //        refCon - this value was passed in during the installation of the isr, since
  417. //                we have globals we do not need to use this
  418. //
  419. //    Output:
  420. //        return kIsrIsComplete always
  421. //
  422. //-----------------------------------------------------------------------------------------
  423.  
  424. InterruptMemberNumber ABCVendorISR(InterruptSetMember member, void *refCon, UInt32 theIntCount)
  425. {
  426. mblk_t            *thePacket;
  427.  
  428. OTEnterInterrupt();        // open transport needs to be notified when entering an interrupt
  429.  
  430. // clear the bit that caused the interrupt
  431.  
  432.     
  433.     // for the transmitter
  434.     // is a packet waiting to be sent, then queue the deferred task
  435. if (gDLPIPrivateData->TxPacketQueue.qHead)
  436.     OTScheduleDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
  437.  
  438.  
  439.     // for the receiver check if anything has come in
  440.     // copy packet from hw into a message block then pass it on
  441.  
  442. //if ((thePacket = allocb(the packet size), BPRI_HI))
  443. //    {
  444.  
  445.         // copy packet into message block
  446. //    bcopy(DMAPtrToPacket, thePacket->b_rptr, the packet size);
  447. //    thePacket->b_wptr += the packet size;
  448. //    Return the dma memory to the dma engine.
  449.  
  450. // or you could use esballoc or OTAllocMsg which will use the DMAPtrToPacket
  451. // you will then get a callback when the client is finished with the dma memory
  452. // Keep in mind that packets could be returned via the callback out of order,
  453. // your dma hw might not be compatiable with this. 
  454. // 
  455.         // put packet on the queue so callback routine can dequeue it and
  456.         // pass it on to upper layers
  457. //    EnqueueElement(&gDLPIPrivateData->RxPacketQueue,(QElem *)thePacket,kNoInterrupts);
  458.     OTScheduleDeferredTask(gDLPIPrivateData->RxDeferredTaskCookie);
  459.     
  460. //    }
  461.  
  462.  
  463.  
  464. OTLeaveInterrupt();        // open transport needs to be notified when leaving an interrupt
  465.  
  466. return kIsrIsComplete;
  467. }
  468.  
  469.